package com.ocm.core.mapping.impl;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import com.googlecode.simpleobjectassembler.ObjectAssembler;
import com.ocm.core.domain.ClassDefinition;
import com.ocm.core.domain.Security;
import com.ocm.core.domain.Security.SecurityElement;
import com.ocm.core.domain.Security.SecurityElements;
import com.ocm.core.domain.UserDetail;
import com.ocm.core.domain.PropertyDefinition;
import com.ocm.core.domain.Storage;
import com.ocm.core.dto.ClassDefinitionDto;
import com.ocm.core.dto.GroupDto;
import com.ocm.core.dto.PropertyDefinitionDto;
import com.ocm.core.dto.SecurityDto;
import com.ocm.core.dto.StorageDto;
import com.ocm.core.dto.UserInfoDto;
import com.ocm.core.mapping.DTOConfiguration;
import com.ocm.core.mapping.DTOService;
import com.ocm.core.mapping.IDMapping;
import com.ocm.core.mapping.MappingConfigure;

@Service("dtoService")
public class DTOServiceImpl implements DTOService {

   private ObjectAssembler objectAssembler;

   private MappingConfigure mappingConfigure;

   @Autowired
   public DTOServiceImpl(@Qualifier("objectAssembler") ObjectAssembler objectAssembler,
         @Qualifier("mappingConfigure") MappingConfigure mappingConfigure) {
      this.objectAssembler = objectAssembler;
      this.mappingConfigure = mappingConfigure;
   }

   private DTOConfiguration createDTOMappingConfigure(DTOConfiguration dtoMappingConfigure) {
      if (dtoMappingConfigure == null)
         dtoMappingConfigure = DTOConfiguration.instance();

      return dtoMappingConfigure;
   }

   public PropertyDefinitionDto convertPropertyDto(PropertyDefinition property, DTOConfiguration dtoMappingConfigure) {
      dtoMappingConfigure = createDTOMappingConfigure(dtoMappingConfigure);
      String[] excludedProperties = mappingConfigure.getPropertiesExcluding(dtoMappingConfigure.getIdMapping());
      PropertyDefinitionDto propertyDto = objectAssembler.assemble(property, PropertyDefinitionDto.class, excludedProperties);
      return propertyDto;
   }

   public ClassDefinitionDto convertClassDto(ClassDefinition classDefinition, DTOConfiguration dtoMappingConfigure) {
      dtoMappingConfigure = createDTOMappingConfigure(dtoMappingConfigure);
      String[] excludedProperties = mappingConfigure.getPropertiesExcluding(dtoMappingConfigure.getIdMapping());
      ClassDefinitionDto classDto = objectAssembler.assemble(classDefinition, ClassDefinitionDto.class, excludedProperties);
      List<SecurityDto> securityDtos = new ArrayList<SecurityDto>();
      Security security = classDefinition.getSecurity();
      if (security != null){
         SecurityElements securityElements = security.getSecurityElements();
         while (securityElements.hasNext()){
            SecurityElement securityElement = securityElements.next();
            SecurityDto securityDto = new SecurityDto();
            securityDto.setAccessMask(securityElement.getAccessMask());
            securityDto.setHasAnonymous(securityElement.getHasAnonymous());
            securityDto.setHasCreator(securityElement.getHasCreator());
            securityDto.setHasGroup(securityElement.getHasGroup());
            securityDto.setHasUser(securityElement.getHasUser());
            securityDto.setUserId(securityElement.getUserId());
            securityDtos.add(securityDto);
         }
      }
      classDto.setSecurities(securityDtos);
      return classDto;
   }

   public List<PropertyDefinitionDto> convertPropertyDtos(List<PropertyDefinition> properties,
         DTOConfiguration dtoMappingConfigure) {
      List<PropertyDefinitionDto> propertyDefDtos = new ArrayList<PropertyDefinitionDto>();
      if (properties != null){
         String[] excludedInstProperties = new String[]{};
         if (dtoMappingConfigure != null && dtoMappingConfigure.getIdMapping() == IDMapping.INST_PROPERTY_EXCLUDED_CONTENTS){
            excludedInstProperties = mappingConfigure.getPropertiesExcluding(dtoMappingConfigure.getIdMapping());
            dtoMappingConfigure = DTOConfiguration.instance();
         }
         if (dtoMappingConfigure != null && dtoMappingConfigure.getIdMapping() == IDMapping.INST_PROPERTY_EXCLUDED_DATA){
            excludedInstProperties = mappingConfigure.getPropertiesExcluding(dtoMappingConfigure.getIdMapping());
            dtoMappingConfigure = DTOConfiguration.instance();
         }
         for (PropertyDefinition propertyDef : properties){
            boolean convert = true;
            for (String instPropertyName : excludedInstProperties){
               if (propertyDef.getName().equals(instPropertyName)){
                  convert = false;
                  break;
               }
            }
            if (convert == true)
               propertyDefDtos.add(this.convertPropertyDto(propertyDef, dtoMappingConfigure));
         }
      }
      return propertyDefDtos;
   }

   public List<ClassDefinitionDto> convertClassDefDtos(List<ClassDefinition> classDefs,
         DTOConfiguration dtoMappingConfigure) {
      List<ClassDefinitionDto> classDefDtos = new ArrayList<ClassDefinitionDto>();
      if (classDefs != null){
         for (ClassDefinition classDef : classDefs){
            classDefDtos.add(this.convertClassDto(classDef, dtoMappingConfigure));
         }
      }
      return classDefDtos;
   }

   public StorageDto convertStorageDto(Storage storage, DTOConfiguration dtoMappingConfigure) {
      dtoMappingConfigure = createDTOMappingConfigure(dtoMappingConfigure);
      String[] excludedProperties = mappingConfigure.getPropertiesExcluding(dtoMappingConfigure.getIdMapping());
      StorageDto storageDto = objectAssembler.assemble(storage, StorageDto.class, excludedProperties);
      return storageDto;
   }

   public GroupDto convertGroupDto(UserDetail group, DTOConfiguration dtoMappingConfigure) {
      dtoMappingConfigure = createDTOMappingConfigure(dtoMappingConfigure);
      String[] excludedProperties = mappingConfigure.getPropertiesExcluding(dtoMappingConfigure.getIdMapping());
      GroupDto groupDto = objectAssembler.assemble(group, GroupDto.class, excludedProperties);
      return groupDto;
   }

   public List<StorageDto> convertStorageDtos(List<Storage> storages, DTOConfiguration dtoMappingConfigure) {
      List<StorageDto> storageDtos = new ArrayList<StorageDto>();
      if (storages != null){
         for (Storage storage : storages){
            storageDtos.add(convertStorageDto(storage, dtoMappingConfigure));
         }
      }
      return storageDtos;
   }

   public String[] getExcludes(DTOConfiguration configuration) {
      DTOConfiguration dtoMappingConfigure = createDTOMappingConfigure(configuration);
      String[] excludedProperties = mappingConfigure.getPropertiesExcluding(dtoMappingConfigure.getIdMapping());
      return excludedProperties;
   }

   public List<GroupDto> convertGroupDtos(List<UserDetail> groups, DTOConfiguration dtoMappingConfigure) {
      List<GroupDto> groupDtos = new ArrayList<GroupDto>();
      if (groupDtos != null){
         for (UserDetail group : groups){
            groupDtos.add(convertGroupDto(group, dtoMappingConfigure));
         }
      }
      return groupDtos;
   }

   public UserInfoDto convertUserDto(UserDetail userInfo, DTOConfiguration dtoMappingConfigure) {
      dtoMappingConfigure = createDTOMappingConfigure(dtoMappingConfigure);
      String[] excludedProperties = mappingConfigure.getPropertiesExcluding(dtoMappingConfigure.getIdMapping());
      UserInfoDto userDto = objectAssembler.assemble(userInfo, UserInfoDto.class, excludedProperties);
      userDto.setIsAccountNonExpired(userInfo.isAccountNonExpired());
      userDto.setIsAccountNonLocked(userInfo.isAccountNonLocked());
      return userDto;
   }

   public List<UserInfoDto> convertUserDtos(List<UserDetail> userInfos, DTOConfiguration dtoMappingConfigure) {
      List<UserInfoDto> userInfoDtos = new ArrayList<UserInfoDto>();
      if (userInfoDtos != null){
         for (UserDetail userInfo : userInfos){
            userInfoDtos.add(convertUserDto(userInfo, dtoMappingConfigure));
         }
      }
      return userInfoDtos;
   }
}
